/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.appyvet.rangebarsample.colorpicker;

import com.appyvet.rangebarsample.utils.LogUtil;

import ohos.agp.colors.HsvColor;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentState;
import ohos.agp.components.StackLayout;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.agp.window.dialog.ToastDialog;
import ohos.agp.window.service.DisplayManager;

import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;

import ohos.app.Context;

import java.io.IOException;

/**
 * This class is responsible to create color circles
 * in color picker dialog
 */
public class CircleView extends StackLayout {
    private static final String TAG = "CircleView";
    private Context mcontext;
    private final int borderWidthSmall;
    private final int borderWidthLarge;

    private final Paint outerPaint;
    private final Paint whitePaint;
    private final Paint innerPaint;
    private boolean selected;

    /**
     * To show color hint in toast
     *
     * @param context the context of app
     * @param colorId the colorId input to get color
     * @return Color the actual color fetch using colorId
     */
    public static Color getColor(Context context, int colorId) {
        if (context == null) {
            return new Color(0);
        }
        try {
            return new Color(context.getResourceManager().getElement(colorId).getColor());
        } catch (IOException | NotExistException | WrongTypeException e) {
            LogUtil.error(TAG, e.getMessage());
        }
        return new Color(0);
    }

    public CircleView(Context context) {
        this(context, null, null);
    }

    public CircleView(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public CircleView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        mcontext = context;
        borderWidthSmall = 10;
        borderWidthLarge = 15;

        whitePaint = new Paint();
        whitePaint.setAntiAlias(true);
        whitePaint.setColor(Color.WHITE);
        innerPaint = new Paint();
        innerPaint.setAntiAlias(true);
        outerPaint = new Paint();
        outerPaint.setAntiAlias(true);

        update(Color.DKGRAY);

        this.addDrawTask(new DrawTask() {
            @Override
            public void onDraw(Component compoent, Canvas canvas) {
                int width = getWidth();
                int height = getHeight();
                int outerRadius = width / 2;
                if (selected) {
                    final int whiteRadius = outerRadius - borderWidthLarge;
                    final int innerRadius = whiteRadius - borderWidthSmall;
                    canvas.drawCircle(width / 2, height / 2, outerRadius, outerPaint);
                    canvas.drawCircle(width / 2, height / 2, whiteRadius, whitePaint);
                    canvas.drawCircle(width / 2, height / 2, innerRadius, innerPaint);
                } else {
                    canvas.drawCircle(width / 2, height / 2, outerRadius, innerPaint);
                }
            }
        });
    }

    private void setNormalRect(Rect destrect, Rect sourcerect) {
        destrect.left = sourcerect.left;
        destrect.top = sourcerect.top;
        destrect.right = sourcerect.right;
        destrect.bottom = sourcerect.bottom;
    }

    private void setRect(RectFloat rectf, Rect rect) {
        rectf.left = rect.left;
        rectf.top = rect.top;
        rectf.right = rect.right;
        rectf.bottom = rect.bottom;
    }

    private void update(int color) {
        update(getColor(mcontext, color));
    }

    /**
     * To show color hint in toast
     *
     * @param color the color
     */
    public void showHint(int color) {
        final int[] screenPos = getLocationOnScreen();
        final Rect displayFrame = new Rect();
        getSelfVisibleRect(displayFrame);
        final int width = getWidth();
        final int height = getHeight();
        final int midy = screenPos[1] + height / 2;
        int referenceX = screenPos[0] + width / 2;
        if (getLayoutDirection() == LayoutDirection.LTR) {
            final int screenWidth = DisplayManager.getInstance()
                    .getDefaultDisplay(mcontext).get().getAttributes().width;

            referenceX = screenWidth - referenceX; // mirror
        }

        ToastDialog toastDialog = new ToastDialog(mcontext);
        toastDialog.setText(String.format("#%06X", 0xFFFFFF & color));

        if (midy < displayFrame.getHeight()) {
            toastDialog.setAlignment(LayoutAlignment.TOP);
        } else {
            toastDialog.setAlignment(LayoutAlignment.BOTTOM);
        }
        toastDialog.show();
    }

    private void update(Color color) {
        innerPaint.setColor(color);
        outerPaint.setColor(new Color(shiftColorDown(color.getValue())));

        Element selector = createSelector(color);
        int[][] states = new int[][]{new int[]{ComponentState.COMPONENT_STATE_PRESSED}};
        setForeground(selector);
    }

    /**
     * To call shift color to change with selected color
     *
     * @param color the color
     * @return int color resource
     */
    public static int shiftColorDown(int color) {
        return shiftColor(color, 0.9f);
    }

    /**
     * To shift color with selected color
     *
     * @param color the color
     * @param by the sifting space
     * @return int color resource
     */
    public static int shiftColor(int color, float by) {
        if (by == 1f) {
            return color;
        }
        HsvColor hsvColor = HsvColor.toHSV(color);
        float value = hsvColor.getValue();
        value *= by;
        int resColor = HsvColor.toColor(hsvColor.getAlpha(), hsvColor.getHue(), hsvColor.getSaturation(), value);
        return resColor;
    }

    /**
     * To set color in background
     *
     * @param color the color which is going to set
     */
    public void setBackgroundColor(Color color) {
        update(color);
        invalidate();
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
        postLayout();
        invalidate();
    }

    private Element createSelector(Color color) {
        int colorPressedGrey = 0x26FFFFFF;

        ShapeElement darkerCircle = new ShapeElement();
        darkerCircle.setShape(ShapeElement.OVAL);
        darkerCircle.setRgbColor(RgbColor.fromArgbInt(colorPressedGrey));
        StateElement stateElement = new StateElement();
        stateElement.addState(new int[]{ComponentState.COMPONENT_STATE_PRESSED}, darkerCircle);

        return stateElement;
    }
}
